/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
1.promise创建时立即执行
2.promise有3种状态pending=>等待,fulfilled=>成功,rejected=>失败
3.使用函数来更改状态resolve,reject(一旦确定不允许更改)
4.then是原型对象方法，可执行成功和失败的回调函数
5.同一个promise,then能被多次调用
6.then方法链式调用
7.then方法识别对象自返回
8.捕获错误
9.then参数可选
10.all方法
11.resolve方法
12.finally方法
13.catch方法
*/
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  //构造器
  constructor(executor) {
    try {
      executor(this.resolve, this.reject); //executor执行器，创建时立即执行
    } catch (error) {
      this.reject(error); //捕获执行器错误
    }
  };

  //状态
  status = PENDING;

  //保存传入值
  value = undefined;
  reason = undefined;

  //保存回调
  successCallback = []; //数组用于多次调用
  failCallback = []; //数组用于多次调用

  //成功
  resolve = value => {
    if (this.status !== PENDING) return; //一旦确定不允许更改
    this.status = FULFILLED;
    this.value = value; //保存成功值

    // if (this.successCallback) this.successCallback(value); 

    while (this.successCallback.length) {
      this.successCallback.shift()(); //处理异步情况,并能多次被调用
    }
  }

  //失败
  reject = reason => {
    if (this.status !== PENDING) return; //一旦确定不允许更改
    this.status = REJECTED;
    this.reason = reason; //保存失败原因

    // if (this.failCallback) this.failCallback(reason); 

    while (this.failCallback.length) {
      this.failCallback.shift()(); //处理异步情况,并能多次被调用
    }
  }

  then(successCallback, failCallback) {
    let promise1 = new MyPromise((resolve, reject) => {
      successCallback = successCallback ? successCallback : value => value; //用于空参数时依次传递参数
      failCallback = failCallback ? failCallback : reason => {
        throw reason
      }; //用于空参数时依次传递参数
      if (this.status === FULFILLED) {
        //状态为成功
        setTimeout(() => {
          try {
            const promise2 = successCallback(this.value); //返回值

            resolvePromise(promise1, promise2, resolve, reject); //如果是普通值直接返回，如果是prmoise对象返回prmoise结果

          } catch (error) {
            reject(error); //捕获then方法错误
          }
        }, 0); //添加异步代码,以免无法在创建过程中获取prmoise2对象自身
      } else if (this.status === REJECTED) {
        //状态为失败
        setTimeout(() => {
          try {

            const promise2 = failCallback(this.reason);

            resolvePromise(promise1, promise2, resolve, reject);

          } catch (error) {
            reject(error); //捕获then方法错误
          }
        }, 0)
      } else {
        //状态为等待(存在异步代码)
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              const promise2 = successCallback(this.value); //返回值

              resolvePromise(promise1, promise2, resolve, reject); //如果是普通值直接返回，如果是prmoise对象返回prmoise结果

            } catch (error) {
              reject(error); //捕获then方法错误
            }
          }, 0); //添加异步代码,以免无法在创建过程中获取prmoise2对象自身
        }); //保存用于处理异步情况,并能多次被调用
        this.failCallback.push(() => {
          setTimeout(() => {
            try {

              const promise2 = failCallback(this.reason);

              resolvePromise(promise1, promise2, resolve, reject);

            } catch (error) {
              reject(error); //捕获then方法错误
            }
          }, 0)
        }); //保存用于处理异步情况,并能多次被调用
      }
    });
    return promise1;
  }

  //无论成功失败都会调用，能链式调用then方法
  finally(callback) {
    return this.then(value => {
      //成功
      return MyPromise.resolve(callback()).then(() => value);

    }, reason => {
      //失败
      return MyPromise.resolve(callback()).then(() => {
        throw reason
      });
    })
  }

  //处理失败回调
  catch (failCallBack) {
    return this.then(undefined, failCallBack);
  }

  //静态方法，接收数组按顺序返回结果，返回值是pormise对象，只要存在状态为rejected返回状态就为rejected
  static all(array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        index++;
        result[key] = value;
        if (index === array.length) { //array中存在异步代码
          resolve(result)
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          //promise对象
          current.then(value => {
            addData(i, value)
          }, reason => {
            //只要存在rejected直接返回reason
            reject(reason)
          })
        } else {
          //普通值
          addData(i, array[i]);
        }
      }
    })
  }

  //静态方法，返回pormise对象
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise((resolve, reject) => {
      resolve(value);
    })
  }
}
/**
 * 解析promise
 * @param {*} promise1 自身对象
 * @param {*} promise2 传入对象
 * @param {*} resolve 成功
 * @param {*} reject 失败
 */
function resolvePromise(promise1, promise2, resolve, reject) {
  if (promise1 === promise2) return reject(new TypeError('Chaining cycle detected for promise #<Promise>')); //如果自己返回自己
  if (promise2 instanceof MyPromise) {
    //promise对象
    promise2.then(value => resolve(value), reason => reject(reason))
  } else {
    //普通值
    resolve(promise2)
  }
}


module.exports = MyPromise;